package com.ptu.spzx.manager.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ptu.spzx.common.exception.ptuException;
import com.ptu.spzx.manager.mapper.SysDeptMapper;
import com.ptu.spzx.manager.mapper.SysDeptUserMapper;
import com.ptu.spzx.manager.mapper.SysRoleUserMapper;
import com.ptu.spzx.manager.mapper.SysUserMapper;
import com.ptu.spzx.manager.service.SysUserService;
import com.ptu.spzx.manager.utils.BeanCopyUtils;
import com.ptu.spzx.manager.utils.RedisCache;
import com.ptu.spzx.manager.utils.SecurityUtils;
import com.ptu.spzx.model.dto.system.*;
import com.ptu.spzx.model.entity.system.SysDept;
import com.ptu.spzx.model.entity.system.SysDeptUser;
import com.ptu.spzx.model.entity.system.SysUser;
import com.ptu.spzx.model.entity.user.UserInfo;
import com.ptu.spzx.model.vo.common.Result;
import com.ptu.spzx.model.vo.common.ResultCodeEnum;
import com.ptu.spzx.model.vo.h5.UserInfoVo;
import com.ptu.spzx.model.vo.system.LoginVo;
import com.ptu.spzx.model.vo.system.SysUserVo;
import com.ptu.spzx.security.pojo.LoginUser;
import com.ptu.utils.AuthContextUtil;
import com.ptu.utils.JwtUtil;
import jakarta.validation.constraints.Max;
import org.apache.poi.util.Units;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    @Autowired
    private SysUserMapper sysUserMapper;


    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private SysRoleUserMapper sysRoleUserMapper;

    @Autowired
    private SysDeptUserMapper sysDeptUserMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Override
    public LoginVo login(LoginDto loginDto) {
//            //获取输入的验证码和存储到Redis的Key的名称
//            String captcha = loginDto.getCaptcha();
//            String key = loginDto.getCodeKey();
//            //2，根据redis里面的key查询到redis里面存储的验证码
//            String redisCode = redisCache.getCacheObject("user:validate"+key);
//            //3，比较输入的验证码和redis里面存储的验证码是否一致
//            if(StrUtil.isEmpty(redisCode)||!StrUtil.equalsIgnoreCase(redisCode,captcha)) {
//                //4 如果不一样，提示用户校验失败
//                throw new ptuException(ResultCodeEnum.VALIDATECODE_ERROR);
//            }
//            //5， 如果校验一致，删除redis里面的验证码
//            redisCache.deleteObject("user:validate" + key);
        //验证密码和用户名是否一致 改用security
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginDto.getUserName(), loginDto.getPassword());
        Authentication authenticate = null;
        try {
            authenticate = authenticationManager.authenticate(authenticationToken);
        } catch (AuthenticationException e) {
            throw new ptuException(ResultCodeEnum.LOGIN_ERROR);
        }
//            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//            if(Objects.isNull(authenticate)){
//                throw new RuntimeException("密码错误");
//            }
        //根据用户的userId生成jwt
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        System.out.println(loginUser);
        String userId = loginUser.getUser().getId().toString();
        String jwt = JwtUtil.createJWT(userId);
        //将用户存入redis 将请求附带jwt
        redisCache.setCacheObject("user:login" + userId, loginUser);
        //放回响应数据
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(loginUser.getUser(), userInfoVo);
        LoginVo loginVo = new LoginVo(jwt, userInfoVo);
        return loginVo;
    }

    @Override
    public void logout() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Long userId = loginUser.getUser().getId();
        redisCache.deleteObject("user:login" + userId);
    }

    @Override
    public PageInfo<SysUser> findByPage(Integer pageNum, Integer pageSize, String keyWord) {
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(keyWord!=null,SysUser::getUserName,keyWord);
        PageHelper.startPage(pageNum, pageSize);
        List<SysUser> sysUsers = sysUserMapper.selectList(lambdaQueryWrapper);
        PageInfo<SysUser> pageInfo = new PageInfo<>(sysUsers);
        return pageInfo;
    }

    //用户添加
    @Override
    public void saveSysUser(SysUserDeptDto sysUserDeptDto) {
        //判断用户名不能重复
//        String userName = sysUserDeptDto.getUserName();
//        SysUser abSysUser = sysUserMapper.selectByUserName(userName);
        List<SysUser> sysUser1 = null;
        if (sysUserDeptDto.getStuId() != null) {
            sysUser1 = sysUserMapper.selectByStuId(sysUserDeptDto.getStuId());
        }
        if (sysUser1.size()!=0) {
            throw new ptuException(ResultCodeEnum.DATA_EXIST);
        }
        SysUser sysUser = BeanCopyUtils.copyBean(sysUserDeptDto, SysUser.class);
        //输入密码
        String hashedPassword = BCrypt.hashpw(sysUserDeptDto.getPassword(), BCrypt.gensalt());
        sysUser.setPassword(hashedPassword);
        //设置statue的值
        sysUser.setStatus(1);
        sysUserMapper.insert(sysUser);
        if (sysUserDeptDto.getDeptId() != null) {
            sysDeptUserMapper.doAssign(sysUser.getId(), sysUserDeptDto.getDeptId());
        }
    }

    @Override
    public void updateSysUser(SysUser sysUser) {
        sysUserMapper.updateById(sysUser);
    }

    @Override
    public void deleteById(List<Long> userId) {
        sysUserMapper.deleteBatchIds(userId);
        for (Long useId : userId) {
            sysDeptUserMapper.deleteByUserId(useId);
            sysRoleUserMapper.deleteByUserId(useId);
        }
        ;
    }

    @Transactional
    @Override
    public void doAssign(AssginRoleDto assginRoleDto) {
        //根据用户id删除之前的数据
        sysRoleUserMapper.deleteByUserId(assginRoleDto.getUserId());
        //重新分配新数据
        List<Long> roleIdList = assginRoleDto.getRoleIdList();
        for (Long roleId : roleIdList) {
            sysRoleUserMapper.doAssign(assginRoleDto.getUserId(), roleId);
        }
    }

    @Transactional
    @Override
    public void doAssignDept(AssginDeptDto assginDeptDto) {
        //根据用户id删除之前的数据
        sysDeptUserMapper.deleteByUserId(assginDeptDto.getUserId());
        //重新分配新数据
        List<Integer> deptIdList = assginDeptDto.getDeptIdList();
        for (Integer deptId : deptIdList) {
            sysDeptUserMapper.doAssign(assginDeptDto.getUserId(), deptId);
        }
    }

    @Override
    public Result userInfo() {
        Long userId = SecurityUtils.getUserId();
        SysUser sysUser = sysUserMapper.selectById(userId);
        SysUserVo sysUserVo = BeanCopyUtils.copyBean(sysUser, SysUserVo.class);
        List<SysDept> SusDepts = sysDeptMapper.findDeptByUserId(userId);
        List<String> deptNames = new ArrayList<>();
        for (SysDept sysDept : SusDepts) {
            String deptName = sysDept.getDeptName();
            deptNames.add(deptName);
        }
        //扩展 目前仅仅限制唯一
        if (deptNames.size() != 1) {
            throw new ptuException(ResultCodeEnum.DATA_ERROR);
        }
        sysUserVo.setCollage(deptNames);
        return Result.build(sysUserVo, ResultCodeEnum.SUCCESS);
    }

    @Override
    public void setClassId(List<String> stuIds, String className) {
        for (String stu : stuIds) {
            sysUserMapper.setClassId(stu, className);
        }
    }

    @Override
    public SysUser getStu(String stuId) {
        if (stuId == null) {
            throw new ptuException(ResultCodeEnum.STU_LESS);
        }
        SysUser userInfo = sysUserMapper.getStu(stuId);
        return userInfo;
    }

    @Override
    public List<SysUser> getStuList(String className) {
        if (className == null) {
            throw new ptuException(ResultCodeEnum.CLASS_LESS);
        }
        List<SysUser> userInfos = sysUserMapper.getStus(className);
        if (userInfos == null) {
            throw new ptuException(ResultCodeEnum.DATA_ERROR);
        }
        return userInfos;
    }

    @Override
    public List<String> getStuListByClass(String className) {
        List<String> stuListByClass = sysUserMapper.getStuListByClass(className);
        return stuListByClass;
    }

    @Override
    public void setClaaNull(String className) {
        sysUserMapper.setClaaNull(className);
    }

    @Override
    public PageInfo<SysUser> getStuListByClassName(List<String> classNames, Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(SysUser::getUserName, SysUser::getPhone, SysUser::getSex, SysUser::getSex, SysUser::getClassName, SysUser::getStatus, SysUser::getId, SysUser::getCreateTime, SysUser::getDescription, SysUser::getUpdateTime, SysUser::getStuId);
        lambdaQueryWrapper.in(SysUser::getClassName, classNames);
        PageHelper.startPage(pageNum, pageSize);
        List<SysUser> userInfos = sysUserMapper.selectList(lambdaQueryWrapper);
        PageInfo<SysUser> userPageInfo = new PageInfo<>(userInfos);
        return userPageInfo;
    }

    @Override
    public List<SysUser> getStuListByAllClassName(List<String> stuIds) {
        List<SysUser> userInfoList = new ArrayList<>();
        for (String stuId : stuIds) {
            List<SysUser> userInfos = sysUserMapper.getStuListByStuId(stuId);
            userInfoList.addAll(userInfos);
        }
        return userInfoList;
    }

    @Override
    public SysUser getStuInfo(String userName) {
        SysUser userInfo = sysUserMapper.selectByUsername(userName);
        return userInfo;
    }

    @Override
    public PageInfo<SysUser> getUserBudeptId(Integer deptId, Integer pageNum, Integer pageSize) {
        SysDept sysDept = sysDeptMapper.selectDeptId(Long.valueOf(deptId));
        if(sysDept==null){
            throw new ptuException(ResultCodeEnum.DATA_NOT_EXIST);
        }
        //子部门的Id;
        List<Integer> sysDepts = sysDeptMapper.selectSonIdS(Long.valueOf(deptId));
        if (sysDepts != null) {
            List<Integer> sysDeptAll=new ArrayList<>();
            sysDeptAll.addAll(sysDepts);
            for(Integer sysDeptId:sysDepts){
                List<Integer> sysDeptss = sysDeptMapper.selectSonIdS(Long.valueOf(sysDeptId));
                if(sysDeptss!=null){
                    sysDeptAll.addAll(sysDeptss);
                }
                for(Integer sys:sysDeptss){
                    List<Integer> syss = sysDeptMapper.selectSonIdS(Long.valueOf(sys));
                    if(syss!=null){
                        sysDeptAll.addAll(syss);
                        System.out.println("线性代数");
                        System.out.println(sysDeptss);
                    }
                }
            }
            sysDeptAll.add(sysDept.getId());
            System.out.println(sysDeptAll);
            LambdaQueryWrapper<SysDeptUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.in(SysDeptUser::getDeptId, sysDeptAll);
            List<SysDeptUser> sysDeptUsers = sysDeptUserMapper.selectList(lambdaQueryWrapper);
            System.out.println("==========");
            System.out.println(sysDeptUsers);
            List<Long> userIds = new ArrayList<>();
            for (SysDeptUser sysDeptUser : sysDeptUsers) {
                Long userId = sysDeptUser.getUserId();
                userIds.add(userId);
            }
            LambdaQueryWrapper<SysUser> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
            lambdaQueryWrapper1.in(SysUser::getId, userIds);
            PageHelper.startPage(pageNum, pageSize);
            List<SysUser> sysUsers = sysUserMapper.selectList(lambdaQueryWrapper1);
            PageInfo<SysUser> pageInfo = new PageInfo<>(sysUsers);
            return pageInfo;
        } else {
            Integer id = sysDept.getId();
            LambdaQueryWrapper<SysDeptUser> lambdaQueryWrapper=new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(SysDeptUser::getDeptId,id);
            List<SysDeptUser> sysDeptUsers = sysDeptUserMapper.selectList(lambdaQueryWrapper);
            List<Long> userIds = new ArrayList<>();
            for (SysDeptUser sysDeptUser : sysDeptUsers) {
                Long userId = sysDeptUser.getUserId();
                userIds.add(userId);
            }
            LambdaQueryWrapper<SysUser> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
            lambdaQueryWrapper1.in(SysUser::getId, userIds);
            PageHelper.startPage(pageNum, pageSize);
            List<SysUser> sysUsers = sysUserMapper.selectList(lambdaQueryWrapper1);
            PageInfo<SysUser> pageInfo = new PageInfo<>(sysUsers);
            return pageInfo;
        }
    }
}
